package com.shuidihuzhu.sdb.helper.log.matter;

import com.shuidihuzhu.sdb.helper.log.utils.AnnotationUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.MDC;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.lang.annotation.*;
import java.lang.reflect.Method;

/**
 * 日志追踪
 */
@Slf4j
@Aspect
@Component
public class LogTraceSimple {

    public static final String mdcKey = "KKK";


    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    @Documented
    public @interface LogTraceAnnotation {
        /**
         * 日志关键字，注意：方法上的关键字会覆盖类上的
         */
        String key() default "";
    }

    @Pointcut("@annotation(com.shuidihuzhu.sdb.helper.log.matter.LogTraceSimple.LogTraceAnnotation)")
    public void doOperation() {
    }

    @Before("doOperation()")
    public void before(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        Method method = signature.getMethod();
        final LogTraceAnnotation annotation = AnnotationUtils.getAnnotation(method, LogTraceAnnotation.class);

        final String keyWords = keyWords(method, joinPoint.getArgs(), annotation);
        if (StringUtils.hasText(keyWords)) {
            MDC.put(mdcKey, keyWords);
        }
    }

    @AfterReturning(value = "doOperation()", returning = "result")
    public void doAfterReturning(JoinPoint joinPoint, Object result) {
        log.debug("日志追踪设置的mdc信息，key:{}, value:{}", mdcKey, MDC.get(mdcKey));
        MDC.remove(mdcKey);
    }

    /**
     * 获取关键字
     * @return
     */
    private String keyWords(Method method, Object param, LogTraceAnnotation lt) {
        if (lt == null || !StringUtils.hasText(lt.key())) {
            if (method == null) {
                return null;
            }
            return String.join(" ", method.getDeclaringClass().getSimpleName(), method.getName());
        }
        if (param == null) {
            return lt.key();
        }

        // el 解析
        final Expression expression = new SpelExpressionParser().parseExpression(lt.key());
        final EvaluationContext context = new StandardEvaluationContext();

        context.setVariable("p", param);
        return expression.getValue(context, String.class);
    }
}
